using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace NssMaterialPropertyDrawer
{
    public class NssShowIfDrawer : MaterialPropertyDrawer
    {
        string mPropertyName;
        float mConditionValue = -1;
        bool mIsShow;
        Color mBackgroundColor = Color.green;
        Color mBackgroundColorForEnum = Color.red;
        string mContent = null;

        public NssShowIfDrawer(string toggleName, float conditionValue)
        {
            mPropertyName = toggleName;
            mConditionValue = conditionValue;
        }

        public NssShowIfDrawer(string toggleName)
        {
            mPropertyName = toggleName;
        }

        public NssShowIfDrawer(string toggleName, float conditionValue, float r, float g, float b)
        {
            mPropertyName = toggleName;
            mConditionValue = conditionValue;
            mBackgroundColorForEnum = mBackgroundColor;
        }

        public NssShowIfDrawer(string toggleName, float r, float g, float b)
        {
            mPropertyName = toggleName;
            mBackgroundColor = new Color(r, g, b);
        }

        override public void OnGUI(Rect pos, MaterialProperty prop, string label, MaterialEditor editor)
        {
            var mat = prop.targets[0] as Material;
            float propValue = mat.GetFloat(mPropertyName);
            mIsShow = false;
            if (mContent == null)
            {
                mContent = "        " + label;
            }

            Color oriBackgroundColor = GUI.backgroundColor;
            
            //Trigger by toggle
            if (mConditionValue < 0)
            {
                bool conditionBool = propValue != 0;
                if (conditionBool)
                {
                    GUI.backgroundColor = mBackgroundColor;
                    mIsShow = true;
                    editor.DefaultShaderProperty(prop, mContent);
                }
            }
            //Trigger by value
            else
            {
                if (mConditionValue == propValue)
                {
                    GUI.backgroundColor = mBackgroundColorForEnum;
                    mIsShow = true;
                    editor.DefaultShaderProperty(prop, label);
                }
            }
            GUI.backgroundColor = oriBackgroundColor;
        }

        override public float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
        {
            return mIsShow ? base.GetPropertyHeight(prop, label, editor) : 0;
        }
    }

    public class NssHideIfDrawer : MaterialPropertyDrawer
    {
        string mPropertyName;
        float mConditionValue = -1;
        bool mIsShow;
        Color mBackgourndColor = Color.gray;

        public NssHideIfDrawer(string toggleName, float conditionValue)
        {
            mPropertyName = toggleName;
            mConditionValue = conditionValue;
        }

        public NssHideIfDrawer(string toggleName)
        {
            mPropertyName = toggleName;
        }

        public NssHideIfDrawer(string toggleName, float conditionValue, float r, float g, float b)
        {
            mPropertyName = toggleName;
            mConditionValue = conditionValue;
            mBackgourndColor = new Color(r, g, b);
        }

        public NssHideIfDrawer(string toggleName, float r, float g, float b)
        {
            mPropertyName = toggleName;
            mBackgourndColor = new Color(r, g, b);
        }

        override public void OnGUI(Rect pos, MaterialProperty prop, string label, MaterialEditor editor)
        {
            var mat = prop.targets[0] as Material;
            float propValue = mat.GetFloat(mPropertyName);
            mIsShow = false;

            Color oriBackgroundColor = GUI.backgroundColor;
            GUI.backgroundColor = mBackgourndColor;
            //Trigger by toggle
            if (mConditionValue < 0)
            {
                bool conditionBool = propValue == 0;
                if (conditionBool)
                {
                    mIsShow = true;
                    editor.DefaultShaderProperty(prop, label);
                }
            }
            //Trigger by value
            else
            {
                if (mConditionValue != propValue)
                {
                    mIsShow = true;
                    editor.DefaultShaderProperty(prop, label);
                }
            }
            GUI.backgroundColor = oriBackgroundColor;
        }

        override public float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
        {
            return mIsShow ? base.GetPropertyHeight(prop, label, editor) : 0;
        }
    }

    public class NssKeywordEnumDrawer : MaterialPropertyDrawer
    {
        enum SpecialFlag
        {
            None,
            RenderMode,
            Count,
        }

        string[] renderMode = { "Opaque", "Transparent"};
        string[] mKeyWords;
        int[] mValues;
        SpecialFlag mFlag;

        public NssKeywordEnumDrawer(float flag)
        {
            if (!ProcessFlag((int)flag))
                Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC, string enumD)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC, enumD };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC, string enumD, string enumE)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC, enumD, enumE };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC, string enumD, string enumE, string enumF)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC, enumD, enumE, enumF };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC, string enumD, string enumE, string enumF, string enumG)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC, enumD, enumE, enumF, enumG };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC, string enumD, string enumE, string enumF, string enumG, string enumH)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC, enumD, enumE, enumF, enumG, enumH };
            Init(mKeyWords);
        }
        public NssKeywordEnumDrawer(string enumA, string enumB, string enumC, string enumD, string enumE, string enumF, string enumG, string enumH, string enumI)
        {
            if (!ProcessFlag(0))
                mKeyWords = new string[] { enumA, enumB, enumC, enumD, enumE, enumF, enumG, enumH, enumI };
            Init(mKeyWords);
        }

        override public void OnGUI(Rect pos, MaterialProperty prop, string label, MaterialEditor editor)
        {
            if (mKeyWords == null)
                return;

            var mat = prop.targets[0] as Material;
            if (mat == null)
                return;

            int keywordIndex = (int)prop.floatValue;
            int keywordsCount = mKeyWords.Length;
            if (keywordIndex >= keywordsCount)
                return;

            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = prop.hasMixedValue;

            //var rect = EditorGUILayout.GetControlRect(true, 16);
            int nameLength = prop.displayName.Length;
            float controlWidth = pos.width;
            pos.width = 150;
            pos.height = 16;
            EditorGUI.LabelField(pos, prop.displayName);

            pos.position = new Vector2(pos.position.x + controlWidth * 0.42f, pos.position.y);
            pos.width = controlWidth - pos.width;
            keywordIndex = EditorGUI.IntPopup(pos, keywordIndex, mKeyWords, mValues);
            EditorGUI.showMixedValue = false;
            if (EditorGUI.EndChangeCheck())
            {
                prop.floatValue = (float)keywordIndex;

                if (!SpecialGUILogicFlow(keywordIndex, mat))
                {
                    for (int i = 0; i < keywordsCount; i++)
                    {
                        if (keywordIndex == i)
                            mat.EnableKeyword(mKeyWords[i]);
                        else
                            mat.DisableKeyword(mKeyWords[i]);
                    }
                }
            }

        }

        private void Init(string[] keyWords)
        {
            if (keyWords != null)
            {
                int length = keyWords.Length;
                mValues = new int[length];
                for (int i = 0; i < length; i++)
                {
                    mValues[i] = i;
                }
            }
        }

        private bool ProcessFlag(int flag)
        {
            if (flag <= 0 || flag >= (int)SpecialFlag.Count)
            {
                mFlag = SpecialFlag.None;
                return false;
            }

            bool result = false;
            mFlag = (SpecialFlag)flag;
            switch (mFlag)
            {
                case SpecialFlag.RenderMode:
                    mKeyWords = renderMode;
                    result = true;
                    break;
                default:
                    result = false;
                    break;
            }

            return result;
        }

        private bool SpecialGUILogicFlow(int keywordIndex, Material mat)
        {
            if (mat == null)
                return false;

            bool result = false;
            switch (mFlag)
            {
                case SpecialFlag.RenderMode:
                    if (keywordIndex == 0)
                    {
                        mat.SetOverrideTag("RenderType", "Opaque");
                        mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
                    }
                    else if (keywordIndex == 1)
                    {
                        mat.SetOverrideTag("RenderType", "Transparent");
                        mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                    }
                    result = true;
                    break;
                default:
                    result = false;
                    break;
            }

            return result;
        }
    }

    public class NssFoldoutDrawer : MaterialPropertyDrawer
    {
        string mKeyword;
        Style mType;
        enum Style
        {
            Foldout,
            FoldoutToggle,
            Count,
        }

        public NssFoldoutDrawer()
        {
            Init(Style.Foldout, null);
        }

        public NssFoldoutDrawer(string keyword)
        {
            Init(Style.FoldoutToggle, keyword);
        }

        private void Init(Style type, string keyword)
        {
            if ((int)type < (int)Style.Count)
            {
                mType = (Style)type;
            }
            else
            {
                this.mType = Style.Foldout;
            }
            this.mKeyword = keyword;
        }

        public override void OnGUI(Rect pos, MaterialProperty prop, string label, MaterialEditor editor)
        {
            bool hasToggle = mType == Style.FoldoutToggle;

            var style = new GUIStyle("ShurikenModuleTitle");// BG
            style.fixedHeight = 35;

            //back box
            var rect = GUILayoutUtility.GetRect(16f, 25f, style);
            rect.yMin -= 5;
            //rect.yMax += 5;
            GUI.Box(rect, "", style);

            //title label
            GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel);// Font
            titleStyle.fontSize += 2;

            EditorGUI.PrefixLabel(new Rect(hasToggle ? rect.x + 50f : rect.x + 25f,rect.y + 6f, 13f, 13f), new GUIContent(label), titleStyle);

            var triangleRect = new Rect(rect.x + 4f, rect.y + 8f, 13f, 13f);// triangle

            var clickRect = new Rect(rect);// click
            //clickRect.height -= 15f;

            var toggleRect = new Rect(triangleRect.x + 20f, triangleRect.y + 0f, 13f, 13f);

            var e = Event.current;
            bool value = prop.floatValue > 0.5 ? true : false;
            EditorGUI.BeginChangeCheck();
            if (e.type == EventType.Repaint)
            {
                EditorStyles.foldout.Draw(triangleRect, false, false, value, false);
                if (hasToggle)
                {
                    if (EditorGUI.showMixedValue)
                        GUI.Toggle(toggleRect, value, "", new GUIStyle("ToggleMixed"));
                    else
                        GUI.Toggle(toggleRect, value, "");
                }
            }

            if (e.type == EventType.MouseDown && (toggleRect.Contains(e.mousePosition) || clickRect.Contains(e.mousePosition)))
            {
                prop.floatValue = prop.floatValue > 0 ? 0.0f : 1.0f;
                e.Use();
            }

            if (EditorGUI.EndChangeCheck() && hasToggle)
            {
                var mat = prop.targets[0] as Material;
                if (mat == null)
                    return;

                //keyword switch
                if (value && !string.IsNullOrEmpty(mKeyword))
                    mat.EnableKeyword(mKeyword);
                else
                    mat.DisableKeyword(mKeyword);
            }
        }
    }

    public class NssHeaderDrawer : MaterialPropertyDrawer
    {
        string mContent;
        Color mContentColor;
        GUIStyle mGUIStyle;

        public NssHeaderDrawer(string content)
        {
            Init(content, GUI.contentColor, 0);
        }

        public NssHeaderDrawer(string content, float r, float g, float b)
        {
            Init(content, new Color(r, g, b), 0);
        }

        public NssHeaderDrawer(string content, float r, float g, float b, float fontSize)
        {
            Init(content, new Color(r, g, b), fontSize);
        }

        void Init(string content, Color fontColor, float fontSize)
        {
            this.mContent = content;
            this.mContentColor = fontColor;
            if (fontSize > 0)
            {
                mGUIStyle = new GUIStyle();
                mGUIStyle.fontSize = (int)fontSize;
                mGUIStyle.normal.textColor = mContentColor;
            }
        }

        public override void OnGUI(Rect pos, MaterialProperty prop, string label, MaterialEditor editor)
        {
            if (mGUIStyle == null)
            {
                Color oriColor = GUI.contentColor;
                GUI.contentColor = mContentColor;
                EditorGUI.LabelField(pos, mContent);
                GUI.contentColor = oriColor;
            }
            else
            {
                EditorGUI.LabelField(pos, mContent, mGUIStyle);
            }

            editor.DefaultShaderProperty(prop, label);
        }
    }

}
